package control.object;

import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import control.character.MyCharacterControl;

/**
 * This control is added to an object while it is being held by a player.
 * It serves to keep the object in front of the player while still obeying some laws of physics.
 */
public class HoldControl extends AbstractControl {
    protected MyCharacterControl holder;

    public HoldControl(MyCharacterControl holder) {
	this.holder = holder;
    }
    
    @Override
    protected void controlUpdate(float tpf) {
	if (enabled && spatial != null) {
	    RigidBodyControl spatialPhysicsControl = spatial.getControl(RigidBodyControl.class);
	    Vector3f viewDirOffset = holder.getViewDirection().normalize().mult(3f);
	    Vector3f locationDiff = holder.getPhysicsLocation().add(viewDirOffset).subtract(spatialPhysicsControl.getPhysicsLocation());
	    locationDiff.multLocal(10f);
	    spatialPhysicsControl.setLinearVelocity(locationDiff);

	    //TODO figure out how to keep spatial from flitting through another object. velocity? sweep test? dunno...
	    //TODO also, stop the object from rotating wildly
	}
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
	//nothing to see here
    }

    @Override
    public Control cloneForSpatial(Spatial spatial) {
	HoldControl control = new HoldControl(spatial.getControl(HoldControl.class).getHolder());
        // copy custom properties here?
        spatial.addControl(control);
        return control;
    }

    public MyCharacterControl getHolder() {
	return holder;
    }

    @Override
    public void setSpatial(Spatial spatial) {
	if(this.spatial == null) {
	    super.setSpatial(spatial);
	    RigidBodyControl rigidBodyControl = this.spatial.getControl(RigidBodyControl.class);
	    if (rigidBodyControl != null) {
		rigidBodyControl.setGravity(Vector3f.ZERO); //remove gravity when adding this control to a spatial
	    }
	} else {
	    RigidBodyControl rigidBodyControl = this.spatial.getControl(RigidBodyControl.class);
	    if (rigidBodyControl != null) {
		rigidBodyControl.setGravity(new Vector3f(0f, -9.8f, 0f)); //restore gravity when removing this control from a spatial
		rigidBodyControl.activate();
	    }
	    super.setSpatial(spatial);
	}
    }
}
